nice_things/async/Future.sh
The Future class implements this popular synchronization primitive for asynchronous programming in pure POSIX sh. The API is inspired by libdex.
Futures—also called Promises in some programming languages—are eager. The async command starts executing from the moment the Future constructor is invoked.
Usage examples
dl_main=#{{{ new Future }}} -n 'main.host' curl https://main.host…
dl_mirror=#{{{ new Future }}} -n 'mirror.host' curl https://mirror.host…
download=#{{{ new Future }}} -n 'download' -o await_any -p "$dl_main" "$dl_mirror"
timeout=#{{{ new Future }}} -n 'timeout 60s' timeout 60
# Either timeout or get result of main/mirror request
if await_first winner "$download" "$timeout"; then
# Futures do not propagate automatically, we must traverse manually to the inner Future
await "$winner" "" dl_winner
Future_get_name "$dl_winner" url
log_debug "Finished downloading from '${url}'"
else
Future_get_name "$winner" name
log_error "Failed to download resource with '${name}' failure"
fi
# Destroy objects to free resources
for future in "$dl_main" "$dl_mirror" "$download" "$timeout"; do
Future_destructor "$future"
done
await
Since 0.3.0 · Source
import "{ await }" from nice_things/async/Future_await.sh
Synopsisawait <&self> [<out_file>] [<out_var>]
Configuration
–
Description
Await the Future to settle. The returned status code is the status of the async command.
When the Future constructor is invoked with the -o option to capture the standard output of the async command, await offers two choices of output variables to get it:
<out_file>to get the path to the file containing the output.<out_var>to get the contents of the output assigned to a variable.
Warning
Note that reading the file when assigning to
<out_var>is done with thereadbuiltin command in pure sh. No external utilities, likecat, are used. This means the assignment should be fast when the output is known to be small, but can get exponentially slower for larger outputs.For this reason, the
<out_var>parameter has limited usefulness to cases when the output of the command is known to be small. For all other cases, the<out_file>parameter should be preferred. Then, you canassignthe contents of the file to a variable with thecatutility, if that is what you need.
Despite the unconventional shorter name, without the Future_ prefix, this implementation of await is an instance method of Future.
Options
–
Operands
<&self>: Self reference.<out_file>: Output variable; the path to the output file will be written to this variable (if-owas specified in theFutureconstructor). Optional, or can be set to the null string to ignore when specifying<out_var>.<out_var>: Output variable; the async command's output will be written to this variable (if-owas specified in theFutureconstructor). Optional.
Stdin
–
Stdout
–
Stderr
–
Exit status
0: The async command completed successfully.>0: The async command failed.12: Invalid self reference<&self>(abort).123: Unexpected error.
Abort
Aborts if self reference <&self> is invalid.
Usage examples
await "$future" output_file
await_all
Since 0.3.0 · Source
import "{ await_all }" from nice_things/async/Future_await_all.sh
Synopsisawait_all <&future>…
Configuration
–
Description
Await all <&future>s to settle. Return status code 0 if all succeeded, otherwise return the status code of the last failure.
Note that await_all always waits until all <&future>s have settled, even if there are early failures. If you want to return early on the first failure, consider the await_all_race function instead.
await_all is not a method, but a static function in the Future class. It can operate on many objects.
Options
–
Operands<&future>: Reference to a Future object.
Stdin
–
Stdout
–
Stderr
–
Exit status
Abort
Aborts if reference <&future> is invalid.
Usage examples
if await_all "$future1" "$future2" "$future3"; then
log_debug "All futures succeeded!"
else
log_warn "Some future failed!"
fi
await_all_race
Since 0.3.0 · Source
import "{ await_all_race }" from nice_things/async/Future_await_all_race.sh
Synopsisawait_all_race <&future>…
Configuration
–
Description
Await all <&future>s to settle. Return status code 0 if all succeeded, otherwise return the status code of the first failure.
Compared to await_all, which always runs through until all <&future>s have settled, await_all_race returns early on the first failure.
await_all_race is not a method, but a static function in the Future class. It can operate on many objects.
Options
–
Operands<&future>: Reference to a Future object.
Stdin
–
Stdout
–
Stderr
–
Exit status
Abort
Aborts if reference <&future> is invalid.
Usage examples
if await_all_race "$future1" "$future2" "$future3"; then
log_debug "All futures succeeded!"
else
log_warn "Some future failed!"
fi
await_any
Since 0.3.0 · Source
import "{ await_any }" from nice_things/async/Future_await_any.sh
Synopsisawait_any {-p | <out_var>} <&future>…
Configuration
–
Description
Await any <&future> to complete successfully. Return status code 0 if any succeeded, otherwise return status code 1 if all failed.
await_any races the <&future>s and returns as soon as one succeeds. A reference to the winning <&future> will be assigned to <out_var>, unless the -p option is specified, in which case the reference will be printed to stdout. It is mandatory to specify one of these two arguments, and they cannot be used together.
await_any is not a method, but a static function in the Future class. It can operate on many objects.
Options-p: Print output instead of assigning to <out_var>.
Operands
<out_var>: Output variable; the result will be written to this variable. Skip when the-poption is specified. Or you can set this to the null string if you don't need a reference to the winningFuture.<&future>: Reference to aFutureobject.
Stdin
–
Stdout
If the -p option is specified, the result is printed to stdout. Otherwise, stdout is not used.
Stderr
–
Exit status
Abort
Aborts if reference <&future> is invalid.
Usage examples
if await_any winner "$future1" "$future2" "$future3"; then
log_debug "The winner is '${winner}'"
else
log_warn "All futures failed!"
fi
await_first
Since 0.3.0 · Source
import "{ await_first }" from nice_things/async/Future_await_first.sh
Synopsisawait_first {-p | <out_var>} <&future>…
Configuration
–
Description
Await any <&future> to settle, no matter if it succeeded or failed. Return status code of the <&future> that settled first.
await_first races the <&future>s and returns as soon as one settles. A reference to the winning <&future> will be assigned to <out_var>, unless the -p option is specified, in which case the reference will be printed to stdout. It is mandatory to specify one of these two arguments, and they cannot be used together.
await_first is not a method, but a static function in the Future class. It can operate on many objects.
Options-p: Print output instead of assigning to <out_var>.
Operands
<out_var>: Output variable; the result will be written to this variable. Skip when the-poption is specified. Or you can set this to the null string if you don't need a reference to the winningFuture.<&future>: Reference to aFutureobject.
Stdin
–
Stdout
If the -p option is specified, the result is printed to stdout. Otherwise, stdout is not used.
Stderr
–
Exit status
0: The firstFutureto settle succeeded.>0: The firstFutureto settle failed.12: Invalid reference (abort).
Abort
Aborts if reference <&future> is invalid.
Usage examples
if await_first winner "$future1" "$future2" "$future3"; then
log_debug "The winner is '${winner}' and it succeeded"
else
log_debug "The winner is '${winner}' and it failed"
fi
Future
Since 0.3.0 · Source
import "{ Future }" from nice_things/async/Future.sh
SynopsisFuture <&self> [-n <name>] [-o] [--] <command> [<arg>…]
Configuration
–
Description
Constructor for the Future class.
Usually, this constructor function should be invoked with the new macro, which takes care of creating the <&self> reference to the newly created object.
Options
-n <name>: Give a name to this object as a way of identifying it.-o: Save the command's standard output to a file.--: End of options.
Operands
<command>: The command to execute asynchronously.<arg>: Optional argument to<command>.
Stdin
–
Stdout
–
Stderr
–
Exit status
0: Successful completion.11: Invalid or missing arguments (abort).12: Invalid self reference<&self>(abort).123: Unexpected error (abort).
Abort
- Aborts on invalid or missing arguments.
- Aborts if self reference
<&self>is invalid. - Aborts on unexpected error.
Usage examples
timer=#{{{ new Future }}} -n 'A 10 seconds timer' sleep 10
Future_destructor
Since 0.3.0 · Source
import "{ Future_destructor }" from nice_things/async/Future_destructor.sh
SynopsisFuture_destructor <&self>
Configuration
–
Description
Clear all data associated with the object.
If the Future has not settled yet, it will be cancelled, by sending a KILL signal to its process.
Options
–
Operands<&self>: Self reference.
Stdin
–
Stdout
–
Stderr
–
Exit status
0: Successful completion.12: Invalid self reference<&self>(abort).
Abort
Aborts if self reference <&self> is invalid.
Usage examples
Future_destructor "$future"
Future_get_name
Since 0.3.0 · Source
import "{ Future_get_name }" from nice_things/collections/Future_get_name.sh
SynopsisFuture_get_name <&self> <out_var>
Configuration
–
Description
Get name of the Future. A Future object only has a name if that was specified in the Future constructor using the -n <name> option.
Options
–
Operands
<&self>: Self reference.<out_var>: Output variable; the result will be written to this variable.
Stdin
–
Stdout
–
Stderr
–
Exit status
0: Successful completion.12: Invalid self reference<&self>(abort).
Abort
Aborts if self reference <&self> is invalid.
Usage examples
Future_get_name "$future" name
Future_is_settled
Since 0.3.0 · Source
import "{ Future_is_settled }" from nice_things/collections/Future_is_settled.sh
SynopsisFuture_is_settled <&self>
Configuration
–
Description
Test synchronously if the Future is already settled at the time of this method's invocation. Return status code 0 if true, 1 if false.
Options
–
Operands<&self>: Self reference.
Stdin
–
Stdout
–
Stderr
–
Exit status
0: TheFutureis already settled.1: TheFutureis not settled yet.12: Invalid self reference<&self>(abort).
Abort
Aborts if self reference <&self> is invalid.
Usage examples
if Future_is_settled "$future"; then
log_debug "The future is already settled"
fi